package gobase

import (
	"fmt"
	"reflect"
	"strings"
)

// 支持所有可比较类型

type MultiSection[T comparable] struct {
	rawSections []string
	startList   []*T
	endList     []*T
	compare     func(val, start, end T) bool
}

// NewMultiSection 创建泛型区间解析器
// 自动根据类型处理比较逻辑，支持所有可比较类型
func NewMultiSection[T comparable](exp string) *MultiSection[T] {
	ms := &MultiSection[T]{}
	if len(exp) > 0 {
		ms.Parse(exp)
	}
	ms.initCompareFunc()
	return ms
}

func (m *MultiSection[T]) initCompareFunc() {
	var testVal T
	// 通过反射获取类型信息
	valType := reflect.TypeOf(testVal)
	switch valType.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		m.compare = m.compareInt
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		m.compare = m.compareUint
	case reflect.Float32, reflect.Float64:
		m.compare = m.compareFloat
	case reflect.String:
		m.compare = m.compareString
	default:
		// 其他可比较类型只支持相等匹配
		m.compare = func(val, start, end T) bool {
			return val == start || val == end
		}
	}
}

func (m *MultiSection[T]) Count() int {
	return len(m.startList)
}

func (m *MultiSection[T]) String() string {
	var sb strings.Builder
	for i := 0; i < len(m.startList); i++ {
		if i > 0 {
			sb.WriteString(",")
		}
		start := m.startList[i]
		end := m.endList[i]
		var str string
		switch {
		case start != nil && end != nil:
			str = fmt.Sprintf("%v~%v", *start, *end)
		case start != nil:
			str = fmt.Sprintf("%v", *start)
		case end != nil:
			str = fmt.Sprintf("~%v", *end)
		}
		sb.WriteString(str)
	}
	return sb.String()
}

// Parse 解析区间表达式
// 自动根据类型处理解析逻辑
// 1,2,33~39
func (m *MultiSection[T]) Parse(exp string) {
	exp = strings.TrimRightFunc(exp, func(r rune) bool {
		return r == ',' || r == ' ' || r == '\r' || r == '\n'
	})
	sections := strings.Split(exp, ",")

	startList := make([]*T, 0, len(sections))
	endList := make([]*T, 0, len(sections))
	rawSections := make([]*string, 0, len(sections))

	for _, sec := range sections {
		str := Trim(sec)
		if str == "" {
			continue
		}
		rawSections = append(rawSections, &str)
		items := strings.SplitN(str, "~", 2)

		// 解析开始值
		if startVal, ok := parseValue[T](items[0]); ok {
			startList = append(startList, &startVal)
		} else {
			startList = append(startList, nil)
		}

		// 解析结束值
		if len(items) == 2 {
			if endVal, ok := parseValue[T](items[1]); ok {
				endList = append(endList, &endVal)
			} else {
				endList = append(endList, nil)
			}
		} else {
			endList = append(endList, nil)
		}
	}

	m.startList = startList
	m.endList = endList
	// 转换rawSections为[]string
	m.rawSections = make([]string, len(rawSections))
	for i, s := range rawSections {
		if s != nil {
			m.rawSections[i] = *s
		}
	}
}

// Contains 判断值是否在区间内，返回对应的原始区间字符串
func (m *MultiSection[T]) Contains(val T) string {
	idx := m.IndexOf(val)
	if idx != -1 && idx < len(m.rawSections) {
		return m.rawSections[idx]
	}
	return ""
}

func (m *MultiSection[T]) In(val T) bool {
	return m.IndexOf(val) >= 0
}

func (m *MultiSection[T]) NotIn(val T) bool {
	return m.IndexOf(val) == -1
}

// IndexOf 查找值所在的区间索引
func (m *MultiSection[T]) IndexOf(val T) int {
	for i := 0; i < len(m.startList); i++ {
		start := m.startList[i]
		end := m.endList[i]

		if start == nil && end == nil {
			continue
		}

		// 处理单值匹配
		if end == nil {
			if *start == val {
				return i
			}
			continue
		}

		// 处理区间匹配
		if start != nil {
			if m.compare(val, *start, *end) {
				return i
			}
		}
	}
	return -1
}

func (m *MultiSection[T]) compareInt(val, start, end T) bool {
	valV := reflect.ValueOf(val)
	startV := reflect.ValueOf(start)
	endV := reflect.ValueOf(end)
	v := valV.Int()
	s := startV.Int()
	e := endV.Int()
	return v >= s && v <= e
}

func (m *MultiSection[T]) compareUint(val, start, end T) bool {
	valV := reflect.ValueOf(val)
	startV := reflect.ValueOf(start)
	endV := reflect.ValueOf(end)
	v := valV.Uint()
	s := startV.Uint()
	e := endV.Uint()
	return v >= s && v <= e
}

func (m *MultiSection[T]) compareFloat(val, start, end T) bool {
	valV := reflect.ValueOf(val)
	startV := reflect.ValueOf(start)
	endV := reflect.ValueOf(end)
	v := valV.Float()
	s := startV.Float()
	e := endV.Float()
	return v >= s && v <= e
}

// 比较字符串类型（字典序）
func (m *MultiSection[T]) compareString(val, start, end T) bool {
	v, ok1 := any(val).(string)
	s, ok2 := any(start).(string)
	e, ok3 := any(end).(string)
	if ok1 && ok2 && ok3 {
		return v >= s && v <= e
	}
	return false
}

// 解析字符串为目标类型
func parseValue[T comparable](s string) (T, bool) {
	var zero T
	if s == "" {
		return zero, false
	}

	valType := reflect.TypeOf(zero)
	switch valType.Kind() {

	case reflect.Int:
		v := StrToIntDef(s, 0)
		return any(v).(T), true
	case reflect.Int8:
		v := int8(StrToInt64Def(s, 0))
		return any(v).(T), true
	case reflect.Int16:
		v := int16(StrToInt64Def(s, 0))
		return any(v).(T), true
	case reflect.Int32:
		v := int32(StrToInt64Def(s, 0))
		return any(v).(T), true
	case reflect.Int64:
		v := StrToInt64Def(s, 0)
		return any(v).(T), true
	case reflect.Uint:
		v := uint(StrToUint64Def(s, 0))
		return any(v).(T), true
	case reflect.Uint8:
		v := uint8(StrToUint64Def(s, 0))
		return any(v).(T), true
	case reflect.Uint16:
		v := uint16(StrToUint64Def(s, 0))
		return any(v).(T), true
	case reflect.Uint32:
		v := uint32(StrToUint64Def(s, 0))
		return any(v).(T), true
	case reflect.Uint64:
		v := uint64(StrToUint64Def(s, 0))
		return any(v).(T), true
	case reflect.Float32:
		v := float32(StrToFloat64Def(s, 0))
		return any(v).(T), true
	case reflect.Float64:
		v := StrToFloat64Def(s, 0)
		return any(v).(T), true
	case reflect.String:
		return any(s).(T), true
	default:
		// 对于其他类型，尝试使用字符串直接转换（如bool）
		if valType.Kind() == reflect.Bool {
			v := TryStrToBool(s, false)
			return any(v).(T), true
		}
		return zero, false
	}
}

// 便捷构造函数 - 避免使用时手动指定类型
func NewIntSection(exp string) *MultiSection[int] {
	return NewMultiSection[int](exp)
}

func NewInt32Section(exp string) *MultiSection[int32] {
	return NewMultiSection[int32](exp)
}

func NewInt64Section(exp string) *MultiSection[int64] {
	return NewMultiSection[int64](exp)
}

func NewFloat32Section(exp string) *MultiSection[float32] {
	return NewMultiSection[float32](exp)
}

func NewFloat64Section(exp string) *MultiSection[float64] {
	return NewMultiSection[float64](exp)
}

func NewStringSection(exp string) *MultiSection[string] {
	return NewMultiSection[string](exp)
}

func NewBoolSection(exp string) *MultiSection[bool] {
	return NewMultiSection[bool](exp)
}
